package cn.dengqiang.user.service.impl;

import cn.dengqiang.basic.exception.BusinessException;
import cn.dengqiang.basic.service.impl.BaseServiceImpl;
import cn.dengqiang.basic.util.AjaxResult;
import cn.dengqiang.basic.util.MD5Utils;
import cn.dengqiang.basic.util.StrUtils;
import cn.dengqiang.user.constant.UserConstants;
import cn.dengqiang.user.constant.WxConstants;
import cn.dengqiang.user.domain.LoginInfo;
import cn.dengqiang.user.domain.User;
import cn.dengqiang.user.domain.WxUser;
import cn.dengqiang.user.dto.LoginDto;
import cn.dengqiang.user.mapper.LoginInfoMapper;
import cn.dengqiang.user.mapper.UserMapper;
import cn.dengqiang.user.mapper.WxUserMapper;
import cn.dengqiang.user.service.ILoginInfoService;
import cn.dengqiang.user.service.IUserService;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class LoginInfoServiceImpl extends BaseServiceImpl<LoginInfo> implements ILoginInfoService {

    @Autowired
    private LoginInfoMapper loginInfoMapper;

    @Autowired
    @Qualifier("redisTemplate")
    private RedisTemplate redisTemplate;
    @Override
    public AjaxResult loginAccount(LoginDto loginDto) {
        //非空判断
        if (StringUtils.isEmpty(loginDto.getUsername())
                ||StringUtils.isEmpty(loginDto.getPassword())
                ||loginDto.getLoginType()==null)
        return AjaxResult.me().setMessage("请输入相关信息在登录");
        //2 从数据库查询 username logintype 用户是否存在，并且状态是否OK
        System.out.println("=======================================");
        LoginInfo info = loginInfoMapper.loadByAcount(loginDto);
        System.out.println(info);
        if (info==null)
            return AjaxResult.me().setMessage("用户名或密码不正确");
        if (info.getDisable()==0)
            return AjaxResult.me().setMessage("账户已被冻结，请联系客服解决");
        String salt = info.getSalt();
        String loginPwd = MD5Utils.encrypByMd5(loginDto.getPassword() + salt);
        if (!info.getPassword().equals(loginPwd))
            return AjaxResult.me().setMessage("用户名或密码不正确");

        String token = UUID.randomUUID().toString();
        //4 存放redis并返回token，其实为了前台不额外发一个请求可以把用户和token一起返回，但是密码要置空
        redisTemplate.opsForValue().set(token,info,30,TimeUnit.MINUTES);
        // 返回token，用户,所以用map返回
        Map<String,Object> result = new HashMap<>();
        result.put("token",token);
        info.setPassword("");
        result.put("loginInfo",info);
        return AjaxResult.me().setResultObj(result);
    }

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private WxUserMapper wxUserMapper;

    @Override
    public AjaxResult loginWechat(Map<String, String> params) {
       //获取code
        String code = params.get("code");
        String binderUrl = params.get("binderUrl");
        //2 获取accessToken
        String getAckUrl = WxConstants.GET_ACK_URL
                .replace("APPID", WxConstants.APPID)
                .replace("SECRET", WxConstants.SECRET)
                .replace("CODE", code);
        String jsonStr = cn.dengqiang.basic.util.HttpClientUtils.httpGet(getAckUrl);
        JSONObject jsonObject = JSONObject.parseObject(jsonStr);
        String accessToken = jsonObject.getString("access_token");
        String openid = jsonObject.getString("openid"); //就相当于微信号

        //3 判断是否已经关联了
        WxUser wxUser = wxUserMapper.loadByOpenId(openid);
        if(wxUser!=null && wxUser.getUser_id()!=null){

            //查询Logininfo
            LoginInfo loginInfo =loginInfoMapper.loadByUserId(wxUser.getUser_id());
            //3.1 如果关联了实现免密登录
            String token = UUID.randomUUID().toString();
            redisTemplate.opsForValue().set(token,loginInfo,30, TimeUnit.MINUTES);
            Map<String,Object> result = new HashMap<>();
            result.put("token",token);
            loginInfo.setSalt(null);
            loginInfo.setPassword(null);
            result.put("loginInfo",loginInfo);
            return AjaxResult.me().setResultObj(result);
        }else{

            //3.2 否则跳转到绑定页面
            binderUrl = binderUrl+"?accessToken="+accessToken+"&openId="+openid;
            return AjaxResult.me().setSuccess(false).setResultObj(binderUrl);
        }

    }

    @Override
    public AjaxResult binderWechat(Map<String, String> params) {
        //参数
        String phone = params.get("phone");
        String verifyCode = params.get("verifyCode");
        String accessToken = params.get("accessToken");
        String openId = params.get("openId");

        //0 验证码比对
        Object codeObj = redisTemplate.opsForValue().get(UserConstants.BINDER_CODE_PREFIX + phone);
        if(codeObj==null){
            return AjaxResult.me().setMessage("请重新获取验证码后再操作！");
        }else{
            String codeStr = (String) codeObj;
            String code = codeStr.split(":")[0];//code：time
            if (!verifyCode.equalsIgnoreCase(code)){
                return AjaxResult.me().setMessage("请输入正确验证码后再操作！");
            }
        }


        //1 获取微信用户信息
        String url = WxConstants.GET_USER_URL
                .replace("ACCESS_TOKEN", accessToken)
                .replace("OPENID", openId);

        String jsonStr = cn.dengqiang.basic.util.HttpClientUtils.httpGet(url);

        //2通过电话和type获取用户登录信息
        LoginDto loginDto = new LoginDto();
        loginDto.setUsername(phone);
        loginDto.setLoginType(1);
        LoginInfo info = loginInfoMapper.loadByPhone(loginDto);
        //3如果用户登录信息不存在
        User user = null;
        if (info==null){
            user = wxUser2User(phone);
            info = user2LoginInfo(user);
            //3.1 创建loginInfo
            loginInfoMapper.save(info);
            //3.2 创建User
            user.setInfo(info);
            userMapper.save(user);
        }else{
            //4用户存在 查询用户
            user = userMapper.loadByPhone(phone);

        }
        //5把用户和wxUser进行绑定
        WxUser wxUser = wxUserJsonStr2WxUser(jsonStr);
        wxUser.setUser_id(user.getId());
        wxUserMapper.save(wxUser);
        //6做免密登录
        //3.1 如果关联了实现免密登录
        String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(token,info,30, TimeUnit.MINUTES);
        Map<String,Object> result = new HashMap<>();
        result.put("token",token);
        info.setSalt(null);
        info.setPassword(null);
        result.put("loginInfo",info);
        return AjaxResult.me().setResultObj(result);
    }

    private WxUser wxUserJsonStr2WxUser(String jsonStr) {
        JSONObject jsonObject = JSONObject.parseObject(jsonStr);
        WxUser wxUser = new WxUser();
        wxUser.setOpenid(jsonObject.getString("openid"));
        wxUser.setNickname(jsonObject.getString("nickname"));
        wxUser.setSex(jsonObject.getInteger("sex"));
        wxUser.setAddress(null);
        wxUser.setHeadimgurl(jsonObject.getString("headimgurl"));
        wxUser.setUnionid(jsonObject.getString("unionid"));
        return wxUser;
    }

    private LoginInfo user2LoginInfo(User user) {
        LoginInfo info = new LoginInfo();
        BeanUtils.copyProperties(user,info); //按照同名原则拷贝属性
        return info;
    }

    private User wxUser2User(String phone) {
        User user = new User();
        user.setUsername(phone);
        user.setPhone(phone);
        user.setEmail(null);
        //给一个随机密码
        String salt = UUID.randomUUID().toString();
        String password = MD5Utils.encrypByMd5(StrUtils.getComplexRandomString(6)+salt);
        user.setPassword(password);
        user.setSalt(salt);
        user.setState(1);
        user.setCreatetime(new Date());
        return user;
    }
}
